home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / master / Examples / Visual / VMake / gadgets.c < prev    next >
C/C++ Source or Header  |  1994-02-01  |  40KB  |  1,086 lines

  1. #include "vmake.h"
  2.  
  3. Prototype int  init_gadgets(void);
  4. Prototype void free_gadget(struct Gadget *gadget);
  5. Prototype void free_gadlist(struct GADLIST *gadlist);
  6. Prototype struct Gadget *create_gadget(struct GADLIST *gadlist,struct G_OBJECT *object,int ulx, int uly,int width);
  7. Prototype void setup_string_gadget(struct Gadget *gad,int base);
  8. Prototype struct Gadget *setup_cycle_gadget(struct Gadget *gad,struct IntuiText *itext,struct G_VALUE *val);
  9. Prototype void reset_list_object(struct G_LIST *list,int active);
  10. Prototype int  setup_list_object(struct GADLIST *gadlist,struct Gadget *gad);
  11. Prototype struct GADLIST *layout_gadgets(struct G_OBJECT *objlist, int ulx, int uly, int width);
  12. Prototype struct Border *build_border(int width, int height, int mode);
  13. Prototype int  init_gad_sizes(int swidth, int sheight, int resize);
  14. Prototype int  create_borders(void);
  15. Prototype int  recalc_group_sizes(struct G_OBJECT *objlist, int *titsize, int *cycsize);
  16. Prototype int  text_width(char *str);
  17.  
  18. /***********************************************************************************
  19.  * Procedure: init_gadgets
  20.  * Synopsis:  rc = init_gadgets();
  21.  * Purpose:   Set up all the base system gadgets for the window.  This includes all
  22.  *            The user defined gadgets as well as the three buttons on the bottom
  23.  ***********************************************************************************/
  24. int init_gadgets()
  25. {
  26.    struct Gadget *gad;
  27.    struct IntuiText *itext;
  28.    int ulx, uly;
  29.    int i;
  30.    int buttons;
  31.  
  32.    global.gadlist = layout_gadgets(global.objects,
  33.                                     global.ri.WindowLeft,
  34.                                     global.ri.WindowTitle,
  35.                                     global.cycsize+global.titsize
  36.                                     );
  37.    if (global.gadlist == NULL) return(1);
  38.    ulx = global.ri.WindowLeft;
  39.    uly = global.height - global.ri.WindowBottom - global.iheight;
  40.  
  41.    buttons = (global.width - (global.ri.WindowLeft + global.ri.WindowRight)) / BUTTON_WIDTH;
  42.    if (buttons > 5) buttons = 5;
  43.  
  44.    for(i = 0; i < buttons; i++)
  45.    {
  46.       global.button[i].base.class = CLASS_BUTTON;
  47.       global.button[i].base.state = i; /* Note that these values correspond to */
  48.                                    /* the BUTTON_xxx equates               */
  49.  
  50.       gad = create_gadget(NULL, (struct G_OBJECT *)(global.button+i),
  51.                                 ulx, uly, BUTTON_WIDTH);
  52.  
  53.       if (gad == NULL) return(1);
  54.       gad->GadgetRender = build_border(BUTTON_WIDTH,
  55.                                        global.iheight, MODE_OUT);
  56.  
  57.       itext = gad->GadgetText;
  58.       itext->LeftEdge += (BUTTON_WIDTH - IntuiTextLength(itext))/2;
  59.  
  60.       gad->NextGadget = global.gadlist->gadgets;
  61.       global.gadlist->gadgets = gad;
  62.       global.gadlist->count++;
  63.  
  64.       gad->GadgetType = BOOLGADGET;
  65.  
  66.       ulx += (global.width - (global.ri.WindowLeft  +
  67.                                global.ri.WindowRight +
  68.                                (buttons*BUTTON_WIDTH)
  69.                               )
  70.              ) / (buttons-1) + BUTTON_WIDTH;
  71.    }
  72.  
  73.    return(0);
  74. }
  75. /***********************************************************************************
  76.  * Procedure: free_gadget
  77.  * Synopsis:  free_gadget(gadget)
  78.  * Purpose:   Free up all memory associated with a gadget
  79.  ***********************************************************************************/
  80. void free_gadget(struct Gadget *gadget)
  81. {
  82.    struct G_OBJECT *obj;
  83.  
  84.    if (gadget)
  85.    {
  86.       obj = (struct G_OBJECT *)(gadget->UserData);
  87.  
  88.       obj->gadget = NULL;
  89.  
  90.       if (obj->class == CLASS_STRING)
  91.       {
  92.          /* We need to free the border structure also */
  93.       }
  94.       free_mem(gadget, sizeof(struct Gadget)+sizeof(struct IntuiText));
  95.    }
  96. }
  97.  
  98. /***********************************************************************************
  99.  * Procedure: free_gadlist
  100.  * Synopsis:  free_gadlist(gadlist)
  101.  * Purpose:   Free up all memory associated with a gadget list created by
  102.  *            layout_gadgets
  103.  ***********************************************************************************/
  104. void free_gadlist(struct GADLIST *gadlist)
  105. {
  106.    struct Gadget *gad, *nextgad;
  107.    struct G_CYCLE *cyc;
  108.    struct G_STRING *str;
  109.  
  110.    if (!gadlist) /* never allocated or already freed */
  111.       return;
  112.  
  113.    for(gad = gadlist->gadgets; gad && gadlist->count; gad = nextgad, gadlist->count--)
  114.    {
  115.       nextgad = gad->NextGadget;
  116.       cyc = (struct G_CYCLE *)gad->UserData;
  117.  
  118.       if ((cyc->base.class & CLASS_MASK) == CLASS_CYCLE)
  119.       {
  120.          /* If there is a string gadget currently in the cycle gadget, we need */
  121.          /* to free it up                                                      */
  122.          if ((str = cyc->curval->string) != NULL)
  123.          {
  124.             free_gadget(str->base.gadget);
  125.          }
  126.       }
  127.       free_gadget(gad);
  128.    }
  129.  
  130.    free_mem(gadlist, sizeof(struct GADLIST));
  131. }
  132.  
  133. /***********************************************************************************
  134.  * Procedure: create_gadget
  135.  * Synopsis:  Gadget = create_gadget(gadlist, object, ulx, uly, width)
  136.  * Purpose:   Create all the appropriate gadgetry and image structures for a list
  137.  *            of gadgets.
  138.  ***********************************************************************************/
  139. struct Gadget *create_gadget(struct GADLIST *gadlist,
  140.                              struct G_OBJECT *object,
  141.                              int ulx, int uly,
  142.                              int width
  143.                             )
  144. {
  145.    struct Gadget *gad;
  146.    struct IntuiText *itext;
  147.  
  148.  
  149.    /* Create a gadget structure and an associated intuitext structure to be */
  150.    /* Layed out on the screen                                               */
  151.    gad = (struct Gadget *)get_mem(sizeof(struct Gadget)+sizeof(struct IntuiText));
  152.    if (gad)
  153.    {
  154.       itext = (struct IntuiText *)(gad+1);
  155.  
  156.       gad->LeftEdge    = ulx;
  157.       gad->TopEdge     = uly;
  158.       gad->Width       = width;
  159.       gad->Height      = global.iheight;
  160.       gad->Flags       = GADGHCOMP;
  161.       gad->Activation  = RELVERIFY;
  162.       gad->GadgetText  = itext;
  163.       gad->UserData    = (APTR)object;
  164.       gad->GadgetID    = object->class; /* set both class and subclass */
  165.       gad->GadgetType   = BOOLGADGET;
  166.  
  167.       object->gadget      = gad;
  168.  
  169.       /* Now we fill in the Intuitext structure */
  170.       itext->FrontPen  = 1;
  171.       itext->BackPen   = 0;
  172.       itext->DrawMode  = JAM1;
  173.       itext->LeftEdge  = 0;
  174.       itext->TopEdge   = (global.iheight - global.ri.FontSize) / 2;
  175.       itext->ITextFont = &global.ri.TextAttr;
  176.       itext->IText     = object->title;
  177.       itext->NextText  = NULL;
  178.  
  179.       if (gadlist)
  180.       {
  181.          gad->NextGadget = gadlist->gadgets;
  182.          gadlist->gadgets = gad;
  183.          gadlist->count++;
  184.       }
  185.    }
  186.  
  187.    return(gad);
  188. }
  189.  
  190. /***********************************************************************************
  191.  * Procedure: setup_string_gadget
  192.  * Synopsis:  setup_string_gadget(gad, string, ulx, uly, width, base)
  193.  * Purpose:   Create all the appropriate gadgetry and image structures for a list
  194.  *            of gadgets.
  195.  ***********************************************************************************/
  196. void setup_string_gadget(struct Gadget *gad,
  197.                          int base
  198.                         )
  199. {
  200.    int wraps;
  201.    int i;
  202.    struct Border *border;
  203.    struct StringInfo *si;
  204.    int sluff;
  205.  
  206.    if (gad == NULL) return;
  207.  
  208.    wraps = (base == CLASS_STRING) ? 2 : 1;
  209.  
  210.    gad->LeftEdge += VBAR*wraps;
  211.    gad->TopEdge  += DHBAR;
  212.    gad->Width    -= DVBAR*wraps;
  213.    gad->Height   -= 2*DHBAR;
  214.  
  215.    sluff = (gad->Height - global.ri.FontSize);
  216.    if (sluff < 0) sluff = 0;
  217.    gad->Height  = global.ri.FontSize;
  218.    gad->TopEdge += sluff / 2;
  219.    if (gad->GadgetText)
  220.    {
  221.       gad->GadgetText->TopEdge -= (DHBAR+sluff);
  222.       gad->GadgetText->LeftEdge -= VBAR*wraps;
  223.    }
  224.  
  225.    if ((base == CLASS_LIST)   ||
  226.        (base == CLASS_STRING) ||
  227.        (base == CLASS_CYCLE))
  228.    {
  229.       for(i=wraps; i > 0; i--)
  230.       {
  231.          /* We need to put a border around the gadget. */
  232.          /* For some string gadgets, we only need a single border */
  233.          /* We can tell this by the base type */
  234.          border = build_border(gad->Width+4*i, gad->Height + sluff + 2*i,
  235.                                (i == 1) ? MODE_IN : MODE_OUT);
  236.          if (border != NULL)
  237.          {
  238.             border->NextBorder->LeftEdge = border->LeftEdge = -2*i;
  239.             border->NextBorder->TopEdge  = border->TopEdge  = -1*i - (sluff/2);
  240.             border->NextBorder->NextBorder = gad->GadgetRender;
  241.             gad->GadgetRender = border;
  242.          }
  243.       }
  244.    }
  245.  
  246.    /* Lastly, we need to setup up the SpecialInfo structure for the string gadget */
  247.    /* If for some reason this fails, we will turn it into a button gadget         */
  248.    si = (struct StringInfo *)get_mem(sizeof(struct StringInfo));
  249.    if (si != NULL)
  250.    {
  251.       gad->SpecialInfo = (APTR)si;
  252.       gad->GadgetType = STRGADGET;
  253.       si->Buffer = ((struct G_STRING *)(gad->UserData))->buf;
  254.       si->MaxChars = MAX_STRING;
  255.    }
  256.    else
  257.       gad->GadgetType = BOOLGADGET;
  258. }
  259.  
  260.  
  261. /***********************************************************************************
  262.  * Procedure: setup_cycle_gadget
  263.  * Synopsis:  gadget = setup_cycle_gadget(gadget, value)
  264.  * Purpose:   Create any subtending string gadgets and correctly position any
  265.  *            cycle value text
  266.  ***********************************************************************************/
  267. struct Gadget *setup_cycle_gadget(struct Gadget *gad,
  268.                                   struct IntuiText *itext,
  269.                                   struct G_VALUE *val
  270.                                  )
  271. {
  272.    struct Gadget *strgad;
  273.    int ilen;
  274.  
  275.    ilen = IntuiTextLength(itext);
  276.  
  277.    if (val->string)
  278.    {
  279.       int x, width;
  280.  
  281.       itext->LeftEdge = CYC_ICON_WIDTH + 2;
  282.       /* We need to create a string gadget to get the input text from */
  283.  
  284.       x = itext->LeftEdge + ilen;
  285.       width = gad->Width - x - 2;
  286.  
  287.       /* Now, create a string gadget and border to put around the gadget */
  288.       strgad = create_gadget(NULL, (struct G_OBJECT *)val->string,
  289.                                        gad->LeftEdge+x, gad->TopEdge, width);
  290.       if (strgad)
  291.       {
  292.          setup_string_gadget(strgad, CLASS_CYCLE);
  293.       }
  294.    }
  295.    else
  296.    {
  297.       strgad = NULL;
  298.       itext->LeftEdge  = (CYC_ICON_WIDTH + gad->Width - ilen) / 2;
  299.    }
  300.    return(strgad);
  301. }
  302. /***********************************************************************************
  303.  * Procedure: reset_list_object
  304.  * Synopsis:  void reset_list_object(list,active);
  305.  * Purpose:   Initialize all the appropriate text pointers for a list gadget
  306.  ***********************************************************************************/
  307. void reset_list_object(struct G_LIST *list,
  308.                        int active
  309.                       )
  310. {
  311.    struct G_ENTRY *ent;
  312.    int i;
  313.  
  314.    ent = list->top;
  315.  
  316.    /* Run through all the entries visible on the screen and for each */
  317.    /* one that is displayed, mark the gadget as selectable.          */
  318.    for(i = 0; i < global.listsize; i++)
  319.    {
  320. /*
  321.       list->btngad[i]->Flags  = (list->btngad[i]->Flags & ~GADGHIGHBITS) |
  322.                                 GADGHNONE;
  323. */
  324.       list->btngad[i]->Flags  = (list->btngad[i]->Flags & ~GADGHIGHBITS) |
  325.                                 GADGHCOMP;
  326.       list->btngad[i]->Height = global.eheight;
  327.       list->strgad[i]->GadgetRender = NULL;
  328.       ((struct StringInfo *)list->strgad[i]->SpecialInfo)->Buffer
  329.               = global.defbuf;  /* because RefreshGlist might write to it... */
  330. /*      global.defbuf[0] = 0; */    /* want this to work like a null string */
  331.  
  332.       /* Is there an entry corresponding to this position on the screen? */
  333.       if (ent)
  334.       {
  335.          /* Certainly is an entry, is it where they want a string gadget ? */
  336.          if (i == active)
  337.          {
  338.             /* Yes, shrink the gadget out of existence so that it doesn't  */
  339.             /* appear on the screen.                                       */
  340. /* prevent mouse activation ?
  341.             list->btngad[i]->Height = 1;
  342. */
  343.             list->strgad[i]->GadgetRender = list->sborder;
  344.          }
  345. /*         else */
  346.          {
  347.             list->btngad[i]->Flags = (list->btngad[i]->Flags & ~GADGHIGHBITS) |
  348.                                      GADGHCOMP;
  349.          }
  350.  
  351.          ((struct StringInfo *)
  352.           list->strgad[i]->SpecialInfo)->Buffer = ent->buf;
  353.          ent = (struct G_ENTRY *)ent->base.next;
  354.       }
  355.    }
  356. }
  357.  
  358. /***********************************************************************************
  359.  * Procedure: setup_list_object
  360.  * Synopsis:  ulx = setup_list_object(gadlist, gadget)
  361.  * Purpose:   Create all the appropriate gadgetry and image structures for a list
  362.  *            object
  363.  ***********************************************************************************/
  364. int setup_list_object(struct GADLIST *gadlist,
  365.                       struct Gadget *gad
  366.                      )
  367. {
  368.    int ulx, uly, alen, dlen, ilen;
  369.    struct G_LIST *list;
  370.    int i;
  371.    char *savetitle;
  372.    struct Gadget *slider, *dngad, *upgad, *addgad, *delgad;
  373.    struct PropInfo *pi;
  374.  
  375. #define ARR_HEIGHT  (7+DHBAR)
  376. #define PROP_WIDTH  (14+DVBAR)
  377.  
  378.    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  379.    /* A list object consists of 8 separate gadgets arranged as below*/
  380.    /* 1: Boolean gadgets that overlay string gadgets.  When the     */
  381.    /* 2:   string gadget is to be active, the height of the boolean */
  382.    /* 3:   gadget is set to 1 exposing the string gadget.           */
  383.    /* 4: A slider gadget to allow positioning in the list           */
  384.    /* 5: An up arrow gadget for moving up one item in the list      */
  385.    /* 6: A Down arrow gadget for moving down one item in the list   */
  386.    /* 7: A NEW gadget for creating an entry in front of current item*/
  387.    /* 8: A DEL gadget for removing the current item from the list.  */
  388.    /*                                                               */
  389.    /*                                                               */
  390.    /*  TITLE TEXT                                                   */
  391.    /* ............................................}+---+            */
  392.    /* ::+---------------------------------------+}}|4  |            */
  393.    /* ::|1                                      |}}|   |            */
  394.    /* ::| I T E M 1                             |}}|   |            */
  395.    /* ::+---------------------------------------+}}| _ |+-------+   */
  396.    /* ::+---------------------------------------+}}|[_]||7      |   */
  397.    /* ::|2                                      |}}|   || N E W |   */
  398.    /* ::| I T E M 2                             |}}+---+|       |   */
  399.    /* ::+---------------------------------------+}}|5^ |+-------+   */
  400.    /* ::+---------------------------------------+}}|/ \|+-------+   */
  401.    /* ::|3                                      |}}+---+|8      |   */
  402.    /* ::| I T E M 3                             |}}|\ /|| D E L |   */
  403.    /* ::+---------------------------------------+}}|6V ||       |   */
  404.    /* :}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}+---++-------+   */
  405.    /*                                                               */
  406.    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  407.    list = (struct G_LIST *)gad->UserData;
  408.  
  409.    /* We need to figure out how big the NEW and DEL gadgets will be */
  410.    alen = ilen = text_width(global.text[TEXT_NEW]);
  411.    dlen = text_width(global.text[TEXT_DEL]);
  412.    if (dlen > ilen) ilen = dlen;
  413.    ilen += 2*DHBAR;
  414.  
  415.    gad->GadgetText->TopEdge   = -global.ri.FontSize;
  416.    gad->TopEdge     += global.ri.FontSize;
  417.    gad->Width       -= ilen + PROP_WIDTH;
  418.    gad->Height       = global.listsize*global.eheight + global.listextra;
  419.    gad->Flags        = GADGHNONE;
  420.    gad->GadgetRender = build_border(gad->Width,
  421.                                     gad->Height,
  422.                                     MODE_OUT);
  423.  
  424.    savetitle = list->base.title;
  425.    list->base.title = "";
  426.  
  427.    uly = gad->TopEdge;
  428.    ulx = gad->LeftEdge + gad->Width;
  429.  
  430.    /* Create the slider and two arrow gadgets.  We will steal the  */
  431.    /* first itext structure and throw it on to the main gadget     */
  432.    slider = create_gadget(gadlist, (struct G_OBJECT *)list,
  433.                                   ulx+DVBAR, uly+DHBAR, PROP_WIDTH-2*DVBAR );
  434.    if (slider == NULL) return(0);
  435.    list->slider = slider;
  436.    slider->Height       = global.listextra + global.listsize*global.eheight -
  437.                           2*ARR_HEIGHT - 2*DHBAR;
  438.    slider->GadgetID     = CLASS_PROP;
  439.    slider->GadgetType   = PROPGADGET;
  440.    slider->Activation |= (GACT_IMMEDIATE | GACT_RELVERIFY | GACT_FOLLOWMOUSE);
  441.    pi = (struct PropInfo *)get_mem(sizeof(struct PropInfo)+
  442.                                            sizeof(struct Image));
  443.    if (pi == NULL) return(0);
  444.    slider->GadgetRender = (struct Image *)(pi+1);
  445.    slider->SpecialInfo  = (APTR)pi;
  446.    pi->Flags = AUTOKNOB | FREEVERT | PROPBORDERLESS;
  447.    recalc_prop(list, &pi->VertBody, &pi->VertPot);
  448.  
  449.    upgad  = create_gadget(gadlist, (struct G_OBJECT *)list,
  450.                                   ulx, uly+slider->Height+2*DHBAR, PROP_WIDTH);
  451.    if (upgad == NULL) return(0);
  452.    upgad->Height       = ARR_HEIGHT;
  453.    upgad->GadgetRender = &global.arrowborder[1];
  454.    upgad->GadgetID     = CLASS_UP;
  455.    upgad->GadgetText   = NULL;
  456.  
  457.    dngad  = create_gadget(gadlist, (struct G_OBJECT *)list,
  458.                                   ulx, upgad->TopEdge+ARR_HEIGHT, PROP_WIDTH);
  459.    if (dngad == NULL) return(0);
  460.    dngad->Height       = ARR_HEIGHT;
  461.    dngad->GadgetRender = &global.arrowborder[0];
  462.    dngad->GadgetID     = CLASS_DOWN;
  463.    dngad->GadgetText   = NULL;
  464.  
  465.    /* Create the ADD/DEL Buttons                                              */
  466.    addgad = create_gadget(gadlist, (struct G_OBJECT *)list, ulx+PROP_WIDTH,
  467.                                   uly + global.listextra + global.listsize*global.eheight-2*global.iheight, ilen);
  468.    if (addgad == NULL) return(0);
  469.    addgad->GadgetRender = build_border(ilen, addgad->Height, MODE_OUT);
  470.    addgad->GadgetID     = CLASS_ADD;
  471.    addgad->GadgetText->LeftEdge += (ilen-alen)>>1;
  472.    addgad->GadgetText->IText = global.text[TEXT_NEW];
  473.  
  474.    delgad = create_gadget(gadlist, (struct G_OBJECT *)list, addgad->LeftEdge,
  475.                                        addgad->TopEdge+addgad->Height, ilen);
  476.    if (delgad == NULL) return(0);
  477.    list->delgad = delgad;
  478.    delgad->GadgetRender = addgad->GadgetRender;
  479.    delgad->GadgetID     = CLASS_DEL;
  480.    if (list->first == NULL)
  481.       delgad->Flags       |= GADGDISABLED;
  482.    delgad->GadgetText->LeftEdge += (ilen-dlen)>>1;
  483.    delgad->GadgetText->IText = global.text[TEXT_DEL];
  484.  
  485.    for(i = 0; i < global.listsize; i++)
  486.    {
  487.       struct Gadget *tgad;
  488.  
  489.       /* Create the string and button gadgets.  Because we insert them on the */
  490.       /* List in reverse order and we want the button gadget to appear first, */
  491.       /* we need to create them in reverse order.                             */
  492.       /* This ordering is assumed in the state changing code.                 */
  493.       tgad = list->strgad[i] = create_gadget(gadlist,
  494.                                              (struct G_OBJECT *)list,
  495.                                              gad->LeftEdge+VBAR, uly,
  496.                                              gad->Width-DVBAR);
  497.       if (tgad == NULL) return(0);
  498.       tgad->GadgetText = NULL;
  499.       tgad->Height = global.eheight;
  500. /* is this appropriate??? */
  501.       tgad->GadgetID   = CLASS_LIST+(i<<SUBCLASS_OFF);
  502.       setup_string_gadget(tgad, CLASS_LIST);
  503.  
  504.       tgad = list->btngad[i] = create_gadget(gadlist,
  505.                                              (struct G_OBJECT *)list,
  506.                                              gad->LeftEdge+VBAR, uly,
  507.                                              gad->Width-DVBAR);
  508.       if (tgad == NULL) return(0);
  509.       tgad->Height     = global.eheight;
  510.       tgad->GadgetText = NULL;
  511.       tgad->GadgetID   = CLASS_LIST+(i<<SUBCLASS_OFF);
  512.       uly += global.eheight;
  513.    }
  514.  
  515.    list->sborder = list->strgad[0]->GadgetRender;
  516.    list->strgad[0]->GadgetRender = NULL;
  517.  
  518.    /* Undo the damage we did to the base object */
  519.    list->base.title = savetitle;
  520.    list->base.gadget = gad;
  521.  
  522.    reset_list_object(list, -1);
  523.  
  524.    return(uly+global.listextra);
  525. }
  526.  
  527. /***********************************************************************************
  528.  * Procedure: layout_gadgets
  529.  * Synopsis:  gadlist = layout_gadgets(objlist, ulx, yly, width);
  530.  * Purpose:   Create all the appropriate gadgetry and image structures for a list
  531.  *            of gadgets.
  532.  ***********************************************************************************/
  533. struct GADLIST *layout_gadgets(struct G_OBJECT *objlist,
  534.                                int ulx, int uly,
  535.                                int width
  536.                               )
  537. {
  538.    struct Gadget *gad;
  539.    struct IntuiText *itext, *itext1;
  540.    int ilen;
  541.    struct G_OBJECT *obj;
  542.    struct GADLIST *gadlist;
  543.  
  544.    if (create_borders()) return(NULL);
  545.  
  546.    gadlist = (struct GADLIST *)get_mem(sizeof(struct GADLIST));
  547.    if (gadlist == NULL) return(NULL);
  548.  
  549.    /* First we need to lay out the gadgets on the left side of the window */
  550.    for(obj = objlist; obj != NULL; obj = obj->next)
  551.    {
  552.       /* Make sure that the gadget will fit on the screen.  We don't even pretend */
  553.       /* To handle the case of a list gadget going over                           */
  554.       if (uly > (global.height - global.ri.WindowBottom - 2*global.iheight))
  555.          return(gadlist);
  556.  
  557.       /* Create a gadget structure and an associated intuitext structure to be */
  558.       /* Layed out on the screen                                               */
  559.       gad = create_gadget(gadlist, obj, ulx, uly, width);
  560.  
  561.       if (gad == NULL) return(gadlist);
  562.  
  563.       itext = (struct IntuiText *)(gad+1);
  564.  
  565.       uly += gad->Height;
  566.  
  567.       ilen = IntuiTextLength(itext);
  568.       switch(obj->class)
  569.       {
  570.          case CLASS_STRING:
  571.             gad->LeftEdge   += global.titsize;
  572.             gad->Width       = global.cycsize;
  573.             itext->LeftEdge  = -ilen;
  574.             setup_string_gadget(gad, CLASS_STRING);
  575.             break;
  576.  
  577.          case CLASS_CYCLE:
  578.             gad->GadgetRender = global.cycborder;
  579.             gad->GadgetType = BOOLGADGET;
  580.             gad->LeftEdge   += global.titsize;
  581.             gad->Width       = global.cycsize;
  582.             itext->LeftEdge  = -ilen;
  583.             itext1 = (struct IntuiText *)get_mem(sizeof(struct IntuiText));
  584.             if (itext1 == NULL) return(gadlist);
  585.             itext1->FrontPen  = 1;
  586.             itext1->BackPen   = 0;
  587.             itext1->DrawMode  = JAM1;
  588.             itext1->LeftEdge  = 0;
  589.             itext1->TopEdge   = 3;
  590.             itext1->ITextFont = &global.ri.TextAttr;
  591.             itext1->IText     = ((struct G_CYCLE *)obj)->curval->title;
  592.             itext1->NextText  = NULL;
  593.             itext1->LeftEdge  = (CYC_ICON_WIDTH+gad->Width-IntuiTextLength(itext1))/2;
  594.  
  595.             itext->NextText   = itext1;
  596.             itext1->IText     = ((struct G_CYCLE *)obj)->curval->title;
  597.             break;
  598.  
  599.          case CLASS_CHECK:
  600.             gad->GadgetType   = BOOLGADGET;
  601.             gad->Width        = CHECK_WIDTH;
  602.             gad->Height       = CHECK_HEIGHT;
  603.             gad->Flags        = GADGHIMAGE;
  604.             if (obj->state & STATE_MASK)   gad->Flags |= SELECTED;
  605.             gad->Activation  |= TOGGLESELECT;
  606.             gad->GadgetRender = global.checkborder[0];
  607.             gad->SelectRender = global.checkborder[1];
  608.             itext->LeftEdge  += CHECK_WIDTH + 4;
  609.             break;
  610.  
  611.          case CLASS_LIST:
  612.             uly = setup_list_object(gadlist, gad);
  613.             if (uly <= 0) return(gadlist);
  614.             break;
  615.  
  616.          default:
  617.             gad->GadgetType = BOOLGADGET;
  618.             break;
  619.       }
  620.    }
  621.    return(gadlist);
  622. }
  623.  
  624. /***********************************************************************************
  625.  * Procedure: build_border
  626.  * Synopsis:  Border = build_border(width, height, mode)
  627.  * Purpose:   Build an return a set of drawing vectors that represent a button of
  628.  *            width and height.  Mode can be either MODE_OUT or MODE_IN
  629.  ***********************************************************************************/
  630. struct Border *build_border(int width,
  631.                             int height,
  632.                             int mode
  633.                            )
  634. {
  635.    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  636.    /*                                                                             */
  637.    /* Select the colors based on the rendering mode.  For an out box, we will use */
  638.    /* the lighter color on the upper and left sides and the darker color on the   */
  639.    /* other two sides.  In an in box, the choice is reversed.                     */
  640.    /*   (x,y)                                                5                    */
  641.    /*   1****************************************************.2                   */
  642.    /*    **4                                               3..                    */
  643.    /*    **                                                 ..                    */
  644.    /*    **                                                 ..                    */
  645.    /*    **                                                 ..                    */
  646.    /*    **                                                 ..                    */
  647.    /*    **3 5                                             4..                    */
  648.    /*   2*....................................................1                   */
  649.    /*                                                       (x+width, y+height)   */
  650.    /* 0.       0,    0    10.   wd,   ht                                          */
  651.    /* 2.       0,   ht    12.   wd,    0                                          */
  652.    /* 4.       1, ht-1    14. wd-1,    1                                          */
  653.    /* 6.       1,    0    16. wd-1,   ht                                          */
  654.    /* 8.    wd-1,    0    18.    1,   ht                                          */
  655.    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  656.  
  657.    struct Border *border, *border1;
  658.    short *vecs;
  659.    int i;
  660.  
  661.    static short inits[] = { 0, 0,   0, 0,   1,-1,   1, 0,  -1, 0,
  662.                             0, 0,   0, 0,  -1, 1,  -1, 0,   1, 0};
  663.  
  664. #define VEC_COUNT 5
  665. #define SINGLEUNIT (sizeof(struct Border)+sizeof(inits))
  666.  
  667.    width--;
  668.    height--;
  669.    border = (struct Border *)get_mem(2*SINGLEUNIT);
  670.    if (border == NULL) return(NULL);
  671.  
  672.    border1 = border+1;
  673.    vecs = (short *)(border+2);
  674.    border->NextBorder = border1;
  675.    border->DrawMode   = JAM1;
  676.    border->Count      = VEC_COUNT;
  677.    border->XY         = vecs;
  678.  
  679.    border1->DrawMode  = JAM1;
  680.    border1->Count     = VEC_COUNT;
  681.    border1->XY        = vecs + (2*VEC_COUNT);
  682.  
  683.    memcpy((char *)vecs, (char *)inits, sizeof(inits));
  684.    for(i = 8; i < 17; i += 2) vecs[i] += width;
  685.    vecs[3]  += height;
  686.    vecs[5]  += height;
  687.    vecs[11] += height;
  688.    vecs[17] += height;
  689.    vecs[19] += height;
  690.  
  691.    if (mode == MODE_OUT)
  692.    {
  693.       border1->FrontPen = global.ri.Shadow;
  694.       border->FrontPen = global.ri.Highlight;
  695.    }
  696.    else
  697.    {
  698.       border1->FrontPen = global.ri.Highlight;
  699.       border->FrontPen  = global.ri.Shadow;
  700.    }
  701.    return(border);
  702. }
  703.  
  704. /***********************************************************************************
  705.  * Procedure: init_gad_sizes
  706.  * Synopsis:  rc = init_gad_sizes(swidth, sheight, resize);
  707.  * Purpose:   Calculate and initialize all the imagery structures
  708.  ***********************************************************************************/
  709. int init_gad_sizes(int swidth,
  710.                    int sheight,
  711.                    int resize)
  712. {
  713.    int i;
  714.    int width, height, wextra, wmarg;
  715.    static int savewidth, saveheight;
  716.  
  717.    wmarg = MARGIN_LEFT + MARGIN_RIGHT;
  718.    if (!resize)          /* not resizing                */
  719.       if (savewidth)     /* and we already have a size  */
  720.          if ((savewidth < swidth) && (saveheight < sheight))
  721.          {               /* and it will fit this screen */
  722.             swidth = savewidth;
  723.             sheight = saveheight;
  724.             resize = 1;  /* trust me...                 */
  725.          }
  726.  
  727.    wmarg += RESIZE_WIDTH + MARGIN_LEFT;
  728.  
  729.    global.listsize = 0;
  730.    /* Make two passes attempting to layout the items.  The first time we will use */
  731.    /* Whatever the prevailing font is.  If this doesn't work, we will switch to a */
  732.    /* Simple TOPAZ80 and try again.  Only if that fails will we give up.          */
  733.    for(i = 5; i >= 0; i--)
  734.    {
  735.       global.iheight = global.ri.TextAttr.ta_YSize+DHBAR;
  736. /* debug - why not try believing TextAttr ? */
  737. /*
  738.       if (global.iheight < global.ri.FontSize)
  739.          global.iheight = global.ri.FontSize;
  740. */
  741.       if (global.iheight < global.ri.FontSize)
  742.          global.ri.FontSize = global.iheight;
  743.  
  744.       if (i)
  745.       {
  746.          global.iheight += 4; /* Account for decent margins on the rendering */
  747.          global.eheight = global.ri.FontSize + 2*DHBAR;
  748.          global.listextra = 0;
  749.       }
  750.       else
  751.       {
  752.          global.iheight += 2; /* Account for decent margins on the rendering */
  753.          global.eheight = global.ri.FontSize + DHBAR + HBAR;
  754.          global.listextra = 1;
  755.       }
  756.  
  757.       /* We have the totals for everything, let's figure out how */
  758.       /* big the final thing is going to be.                     */
  759.       height = recalc_group_sizes(global.objects, &global.titsize, &global.cycsize)+
  760.                global.iheight + MARGIN_MID +  /* Gadgets on the bottom */
  761.                global.ri.WindowTitle + global.ri.WindowBottom;
  762.  
  763.       width  = global.cycsize + global.titsize + wmarg;           
  764.  
  765.       if ((wextra = (width - swidth)) > 0)
  766.          {
  767.          if (wextra < global.titsize)
  768.             global.titsize -= wextra;
  769.          else
  770.              global.titsize = 0;
  771.          }
  772.  
  773.       if ((i == 5) && (height <= sheight))
  774.       {
  775.          int num;
  776.          num = (sheight - height) / global.eheight;
  777.          if (num < 3)
  778.          {
  779.             height = sheight + 1; /* Force a failure */
  780.          }
  781.          else
  782.          {
  783.             if (!resize) /* first time in go for medium size */
  784.             {
  785.                if (num > 10) num = 10;
  786.             }
  787.             else
  788.                if (num > MAX_LIST) num = MAX_LIST;
  789.             global.listsize = num;
  790.             height += num*global.eheight;
  791.          }
  792.       }
  793.  
  794.       if (height <= sheight) break;
  795.       /* can we do anything here about insufficient width ? */
  796.  
  797.       switch(i)
  798.       {
  799.          case 0:
  800.             break;
  801.          case 1:
  802.          case 2:
  803.             /* Set up so we try with Topaz 80 as our default font the second time around */
  804.             global.ri.TextAttr = TOPAZ80;
  805.             break;
  806.          case 5:
  807.             global.listsize = 9;
  808.             break;
  809.          default:
  810.             global.listsize = (global.listsize / 2) + 1;
  811.             if (global.listsize < 3) global.listsize = 3;
  812.             break;
  813.       }
  814.    }
  815.  
  816.    /* Everything worked out fine, let us set the height of the window */
  817.    global.width = resize ? swidth : width;
  818.    global.height = resize ? sheight : height;
  819.    savewidth = global.width;
  820.    saveheight = global.height;
  821.  
  822.    /* Also see if we need to adjust the titsize and cycsize values */
  823.    i = global.width - width;
  824.    if (i > 0)
  825.       global.cycsize += i;
  826.  
  827.    return(0);
  828. }
  829.  
  830.  
  831. /***********************************************************************************
  832.  * Procedure: create_borders
  833.  * Synopsis:  create_borders
  834.  * Purpose:   Create the borders for all the gadgets
  835.  ***********************************************************************************/
  836. int create_borders()
  837. {
  838.    struct Border *border;
  839.    /* * * * * * * * * * * * * * * * * * * * * * * * * * */
  840.    /*                                                   */
  841.    /*              11111111                11111111     */
  842.    /*    012345678901234567      012345678901234567     */
  843.    /*    =================#      =================# 0   */
  844.    /*    ||......23......##      ||..18......54..## 1   */
  845.    /*    ||......##......##      ||..##......##..## 2   */
  846.    /*    ||.....####.....##      ||...##....##...## 3   */
  847.    /*    ||....##76##....##      ||....##76##....## 4   */
  848.    /*    ||...##....##...##      ||.....####.....## 5   */
  849.    /*    ||..##......##..##      ||......##......## 6   */
  850.    /*    ||..18......54..##      ||......23......## 7   */
  851.    /*    |#################      |################# 8   */
  852.    /*                                                   */
  853.    /* * * * * * * * * * * * * * * * * * * * * * * * * * */
  854.    static short Up_Vectors[] = { 4,6,  8,2,  9,2, 13,6, 12,6,  9,3,  8,3,  5,6 };
  855.    static short Dn_Vectors[] = { 4,2,  8,6,  9,6, 13,2, 12,2,  9,5,  8,5,  5,2 };
  856.  
  857.    /* * * * * * * * * * * * * * * * * * */
  858.    /*              11111111112222       */
  859.    /*    012345678901234567890134       */
  860.    /*    ========================== 0   */
  861.    /*    ||.....7.....8..........   1   */
  862.    /*    ||.....#######......#|..   2   */
  863.    /*    ||...5##.....##d....#|..   3   */
  864.    /*    ||....##.....##.....#|..   4   */
  865.    /*    ||....##..a######b..#|..   5   */
  866.    /*    ||....##....####....#|..   6   */
  867.    /*    ||....##....9##c....#|..   7   */
  868.    /*    ||....##............#|..   8   */
  869.    /*    ||...4##6...0##1....#|..   9   */
  870.    /*    ||.....#######......#|..   10  */
  871.    /*    ||.....3.....2..........   11  */
  872.    /*    |########################  12  */
  873.    /*                                   */
  874.    /* * * * * * * * * * * * * * * * * * */
  875.    static short Cycle_Vectors[] = { 13, 9,  14, 9,  13,10,   7,10,   6, 9,
  876.                                      6, 3,   7, 9,   7, 2,  13, 2,  13, 7,
  877.                                     11, 5,  16, 5,  14, 7,  14, 3, };
  878.    static short Cycle_Line1[]   = { 20, 2,  20,11};
  879.    static short Cycle_Line2[]   = { 21, 2,  21,11};
  880.  
  881.    static short Check_Vectors[] = { 19, 2,  17, 2,  11, 8,   8, 5,   7, 5,
  882.                                     10, 8,   9, 5,  12, 8,  18, 2 };
  883.  
  884.    /* Now we have calculated sizes for the objects, layout the border structures */
  885.  
  886.    /* Create a border for the cycle gadgets */
  887.    global.cycborder = build_border(global.cycsize,
  888.                                        global.iheight, MODE_OUT);
  889.    /* We also need to put in the vectors for the cycle picture */
  890.    border = (struct Border *)get_mem(5*sizeof(struct Border));
  891.    if (border == NULL) return(1);
  892.  
  893.    border[0].NextBorder = border+1;
  894.    border[1].NextBorder = border+2;
  895.    border[2].NextBorder = global.cycborder;
  896.    global.cycborder = border;
  897.  
  898.    border[0].DrawMode = JAM1;
  899.    border[0].Count  = sizeof(Cycle_Vectors)/(2*sizeof(short));
  900.    border[0].XY = Cycle_Vectors;
  901.    border[0].FrontPen = 1;
  902.  
  903.    border[1].DrawMode = JAM1;
  904.    border[1].Count  = sizeof(Cycle_Line1)/(2*sizeof(short));
  905.    border[1].XY = Cycle_Line1;
  906.    border[1].FrontPen = global.ri.Shadow;
  907.  
  908.    border[2].DrawMode = JAM1;
  909.    border[2].Count  = sizeof(Cycle_Line2)/(2*sizeof(short));
  910.    border[2].XY = Cycle_Line2;
  911.    border[2].FrontPen = global.ri.Highlight;
  912.  
  913.    global.checkborder[0] = border+3;
  914.    border[3].NextBorder = build_border(CHECK_WIDTH, CHECK_HEIGHT, MODE_OUT);
  915.    border[3].DrawMode = JAM1;
  916.    border[3].Count = sizeof(Check_Vectors)/(2*sizeof(short));
  917.    border[3].XY = Check_Vectors;
  918.    border[3].FrontPen = 0;
  919.  
  920.    global.checkborder[1] = border+4;
  921.    border[4].NextBorder = build_border(CHECK_WIDTH, CHECK_HEIGHT, MODE_OUT);
  922.    border[4].DrawMode = JAM1;
  923.    border[4].Count = sizeof(Check_Vectors)/(2*sizeof(short));
  924.    border[4].XY = Check_Vectors;
  925.    border[4].FrontPen = 1;
  926.  
  927.    /* Adjust the height of the cycle vectors to the current height */
  928.    /* See the picture above for these values.  Yes, they are hard  */
  929.    /* coded magic values, but equates for them don't make a lot of */
  930.    /* sense in a situation like this.                              */
  931.    {
  932.       int cheight;
  933.       if (global.iheight > 11)
  934.          cheight = global.iheight;
  935.       else
  936.          cheight = 11;
  937.       cheight -= DHBAR;
  938.       Cycle_Vectors[1] = cheight - 2;
  939.       Cycle_Vectors[3] = cheight - 2;
  940.       Cycle_Vectors[5] = cheight - 1;
  941.       Cycle_Vectors[7] = cheight - 1;
  942.       Cycle_Vectors[9] = cheight - 2;
  943.       Cycle_Vectors[13] = cheight - 2;
  944.    }
  945. /*
  946.    for(i = 0; i < 0x0d; i++)
  947.    {
  948.       int extra;
  949.  
  950.       extra = global.iheight - 13;
  951.       if (i > 8)
  952.       {
  953.          extra >>= 1;
  954.       }
  955.       else if ((i > 6) || (i == 5))
  956.       {
  957.          extra = 0;
  958.       }
  959.  
  960.       Cycle_Vectors[1+i*2] += extra;
  961.    }
  962. */
  963.  
  964.    Cycle_Line2[3] = Cycle_Line1[3] = (global.iheight - 1) - DHBAR;
  965.  
  966.    {
  967.       int bheight;
  968.       bheight = (global.listsize*global.eheight) - (2*ARR_HEIGHT) + global.listextra;
  969.       border = build_border(PROP_WIDTH, bheight, MODE_OUT);
  970.       if (border == NULL) return(1);
  971.  
  972.       border->TopEdge -= bheight;
  973.       border->NextBorder->TopEdge -= bheight;
  974.    }
  975.  
  976.    global.arrowborder[0].NextBorder = build_border(PROP_WIDTH, ARR_HEIGHT, MODE_OUT);
  977.    global.arrowborder[1].NextBorder = border;
  978.    border->NextBorder->NextBorder = global.arrowborder[0].NextBorder;
  979.  
  980.    global.arrowborder[0].DrawMode = JAM1;
  981.    global.arrowborder[0].Count  = sizeof(Dn_Vectors)/(2*sizeof(short));
  982.    global.arrowborder[0].XY = Dn_Vectors;
  983.    global.arrowborder[0].FrontPen = 1;
  984.  
  985.    global.arrowborder[1].DrawMode = JAM1;
  986.    global.arrowborder[1].Count  = sizeof(Up_Vectors)/(2*sizeof(short));
  987.    global.arrowborder[1].XY = Up_Vectors;
  988.    global.arrowborder[1].FrontPen = 1;
  989.    return(0);
  990. }
  991.  
  992. /***********************************************************************************
  993.  * Procedure: recalc_group_sizes
  994.  * Synopsis:  recalc_group_sizes(objlist, &titsize, &cycsize)
  995.  * Purpose:   Calculate the base sizes for different types of objects.
  996.  *            We need to calculate the width for CYCLE titles and size for cycles
  997.  *            Everything else has a fixed size to be used anyway.
  998.  ***********************************************************************************/
  999. int recalc_group_sizes(struct G_OBJECT *objlist,
  1000.                     int *titsize,
  1001.                     int *cycsize)
  1002. {
  1003.    int wid;
  1004.    int height;
  1005.    struct G_OBJECT *obj;
  1006.    struct G_CYCLE *cyc;
  1007.    struct G_VALUE *val;
  1008.  
  1009.    *titsize = 0;
  1010.    *cycsize = 0;
  1011.    height = 0;
  1012.  
  1013.    /* First we need to lay out the gadgets on the left side of the window */
  1014.    for(obj = objlist; obj != NULL; obj = obj->next)
  1015.    {
  1016.       switch(obj->class)
  1017.       {
  1018.          case CLASS_CYCLE:
  1019.             /* go through and get all the cycle values */
  1020.             cyc = (struct G_CYCLE *)obj;
  1021.             set_cyc_state(cyc, cyc->curval);
  1022.             for(val = cyc->values; val != NULL; val = val->next)
  1023.             {
  1024.                wid = text_width(val->title);
  1025.                if (val->string)
  1026.                {
  1027.                   char *p;
  1028.                   int num;
  1029.  
  1030.                   p = strchr(val->option, '%');
  1031.                   num = 0;
  1032.                   if (p)
  1033.                   {
  1034.                      p++;
  1035.                      while ((*p >= '0') && (*p <= '9'))
  1036.                         num = (num * 10) + *p++ - '0';
  1037.                   }
  1038.                   if (num <= 0) num = 3;
  1039.                      wid += (text_width("0") * (num+1)) + DVBAR;
  1040.                }
  1041.                if (wid > *cycsize) *cycsize = wid;
  1042.             }
  1043.             /* Fall through and get the title size */
  1044.          case CLASS_STRING:
  1045.             wid = text_width(obj->title);
  1046.             if (wid > *titsize) *titsize = wid;
  1047.             break;
  1048.          case CLASS_LIST:
  1049.             height += global.eheight * global.listsize;
  1050.             break;
  1051.          case CLASS_CHECK:
  1052.             break;
  1053.          default:
  1054.             printf("Huh\n");
  1055.             break;
  1056.       }
  1057.       height += global.iheight;
  1058.    }
  1059.    *titsize += DVBAR;
  1060.    *cycsize += CYC_ICON_WIDTH+DVBAR;
  1061.  
  1062.    return(height);
  1063. }
  1064.  
  1065. /***********************************************************************************
  1066.  * Procedure: text_width
  1067.  * Synopsis:  len = text_width(str)
  1068.  * Purpose:   Return the rendered width of a given string
  1069.  ***********************************************************************************/
  1070. int text_width(char *str
  1071.               )
  1072. {
  1073.    struct IntuiText itext;
  1074.  
  1075.    itext.FrontPen  = 1;
  1076.    itext.BackPen   = 0;
  1077.    itext.DrawMode  = JAM1;
  1078.    itext.LeftEdge  = 0;
  1079.    itext.TopEdge   = 1;
  1080.    itext.ITextFont = &global.ri.TextAttr;
  1081.    itext.NextText  = NULL;
  1082.    itext.IText     = str;
  1083.  
  1084.    return(IntuiTextLength(&itext));
  1085. }
  1086.